﻿using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace PC.PickleJar.DebugInstaller
{
	public class TestClassExtensionRegistrationHelper
	{
		public TestClassExtensionRegistrationHelper()
		{
		}

		public void Register(Type testClassExtensionType, String visualStudioVersion)
		{
			TestClassExtensionRegistrationHelper.CopyFiles(testClassExtensionType, visualStudioVersion);
			TestClassExtensionRegistrationHelper.RegisterExtension(testClassExtensionType, visualStudioVersion);
		}

		private static void CopyFiles(Type testClassExtensionType, String visualStudioVersion)
		{
			var vsKey = Registry.LocalMachine.OpenSubKey(
				String.Format(
					CultureInfo.InvariantCulture,
					@"SOFTWARE\Microsoft\VisualStudio\{0}\",
					visualStudioVersion));
			String installDir = (String)vsKey.GetValue("InstallDir");

			DirectoryInfo targetDirectory = new DirectoryInfo(Path.Combine(installDir, "PublicAssemblies"));
			if (!targetDirectory.Exists)
			{
				throw new InvalidOperationException("Could not find PublicAssemblies folder.");
			}

			List<FileInfo> files = new List<FileInfo>();
			var dll = new FileInfo(Assembly.GetAssembly(testClassExtensionType).Location);
			var pdb = new FileInfo(
				Path.Combine(
					dll.DirectoryName,
					Path.GetFileNameWithoutExtension(dll.FullName) + ".pdb"));
			files.Add(dll);
			//files.Add(pdb);

			foreach (var file in files.Where(item => item.Exists))
			{
				var targetFile = new FileInfo(Path.Combine(targetDirectory.FullName, file.Name));

				if (targetFile.Exists && targetFile.LastWriteTime < file.LastWriteTime)
				{
					targetFile.Delete();
				}

				if (!targetFile.Exists)
				{
					file.CopyTo(targetFile.FullName, true);
				}
			}
		}

		private static void RegisterExtension(Type testClassExtension, String visualStudioVersion)
		{
			List<RegistryKey> targetKeys = new List<RegistryKey>();
			targetKeys.Add(
				Registry.LocalMachine.OpenSubKey(
					TestClassExtensionRegistrationHelper.GetSubKeyString(false, visualStudioVersion, false), true));
			targetKeys.Add(
				Registry.LocalMachine.OpenSubKey(
					TestClassExtensionRegistrationHelper.GetSubKeyString(true, visualStudioVersion, false), true));
			targetKeys.Add(
				Registry.CurrentUser.OpenSubKey(
					TestClassExtensionRegistrationHelper.GetSubKeyString(false, visualStudioVersion, true), true));
			targetKeys.Add(
				Registry.CurrentUser.OpenSubKey(
					TestClassExtensionRegistrationHelper.GetSubKeyString(true, visualStudioVersion, true), true));

			foreach (var key in targetKeys.Where(item => item != null))
			{
				var pickleKey = key.CreateSubKey(testClassExtension.Name);
				pickleKey.SetValue("AttributeProvider", testClassExtension.AssemblyQualifiedName, RegistryValueKind.String);
			}
		}

		private static string GetSubKeyString(bool isWow, String vsVersion, bool isCurrentUser)
		{
			String result =
						 String.Concat(
							 String.Format(
								 CultureInfo.InvariantCulture,
								 @"SOFTWARE\{0}Microsoft\VisualStudio\{1}{2}\EnterpriseTools\QualityTools\TestTypes\",
								 isWow ? @"Wow6432Node\" : String.Empty,
								 vsVersion,
								 isCurrentUser ? @"_Config\" : String.Empty),
							 @"{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\TestTypeExtensions\");
			return result;
		}
	}
}
